package mirabilis.org;

import java.io.ObjectInputStream.GetField;
import java.util.Iterator;

import org.jblas.DoubleMatrix;
import org.jblas.Solve;

import mirabilis.org.config.Configuration;
import mirabilis.org.config.LoadProperties;
import mirabilis.org.simplices.Coordinates;
import mirabilis.org.simplices.Simplex;
import mirabilis.org.simplices.Vertex;
import mirabilis.org.util.Bounds;
import mirabilis.org.util.Gradients;
import mirabilis.org.util.Initialization;
import mirabilis.org.util.Line;
import mirabilis.samples.cec2014.Cec2014;


public class BlindArcher {
	

	
	//Initialization:
	// It provides the initial n-simplex for
	// Bound constraints for any given x with x ≥ l y x ≤ u. The lu matrix has to be 
	// The first com
	public static double[][] init_blindarcher(int n, double[] lu){
		return null;
	}
	
	
	//TODO: Pass all required arguments and log the results. Wrap all the functionality around this function
	public static void blindarcher(LoadProperties lp){
		Configuration.setConfiguration(lp);
		Configuration.setBounds();
		
	}
	
	//TODO: Run Blind Archer as a framework
	public static void main(String[] args) {
		//Setting up properties
				LoadProperties lp = new LoadProperties(args);
				Configuration.setConfiguration(lp);	
				Configuration.F=2;
				Configuration.minimization = true;
				Configuration.N=2;
				Configuration.upper_bound= 100;
				Configuration.lower_bound= -100;
				Configuration.setBounds();
					
				//Testing the structure of the first simplex
				Cec2014 bench = new Cec2014();

				
				Simplex simplex = new Simplex(bench,true);
				// --- Starting hack
//					double p1x = 100;//CommonState.r.nextDouble()*scaleratio+Configuration.lower_bound;
//					double p1y = -100;//CommonState.r.nextDouble()*scaleratio+Configuration.lower_bound;
//				
//					double p2x = 0;//CommonState.r.nextDouble()*scaleratio+Configuration.lower_bound;
//					double p2y = -100;//CommonState.r.nextDouble()*scaleratio+Configuration.lower_bound;
//
//					double p3x = 100;//CommonState.r.nextDouble()*scaleratio+Configuration.lower_bound;
//					double p3y = 0;//CommonState.r.nextDouble()*scaleratio+Configuration.lower_bound;
//
//					while(!simplex.isEmpty())
//						simplex.pollArrow();
//				
//					double[] coordinates1 = {p1x,p1y};
//					simplex.addVertex(coordinates1);
//					double[] coordinates2 = {p2x,p2y};
//					simplex.addVertex(coordinates2);
//					double[] coordinates3 = {p3x,p3y};
//					simplex.addVertex(coordinates3);
				
				// ---- end hack
				
//				for (Iterator<Vertex> it = simplex.iterator(); it.hasNext();){
//					Vertex y_n = it.next();
//					try {
//						System.out.println(y_n.getCoordinates().asString()+" "+y_n.getFitness());
//					} catch (Exception e) {	e.printStackTrace();}
//				}
				
				//simplex.pollArrow();
				//double[] zero = {0,0};
				//simplex.addVertex(zero);
				
				double initialVolume = Initialization.simplex_volume(Configuration.N, Gradients.hackToGoArrayContainingASimplex(simplex));
				System.out.println(simplex.asString()+" "+initialVolume);
				//System.out.println(volumeSimplex);
				//Vertex bullseye = null;
				//double[] trustedbow = null;
				
				for(int i=0;i<100;i++){
				
					double volumeSimplex = shootandaim(simplex);
					
					//bullseye = method2(simplex, bullseye);
					
					//trustedbow = method4(simplex, trustedbow);
					
					//System.out.println("eeoo");
				
					try {
						System.out.println(simplex.asString()+volumeSimplex);
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}


				}	
				
				try {
					System.out.println(simplex.getBest().getFitness());
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
	}
	
	//Correction with true gradients
	// mantaining 1/2 - 1
	public static double shootandaim(Simplex simplex){
		
		double[] gradients = Gradients.unit_gradient(simplex);
		double volumeSimplex = Initialization.simplex_volume(Configuration.N, Gradients.hackToGoArrayContainingASimplex(simplex));
		//Simplex without the arrow
		double[] centroid = Gradients.centroid(simplex);
		Vertex arrow = simplex.pollArrow();
		double[] bow = Gradients.getBowHyperplane(simplex);
		double[] gradient_stabilizer = Gradients.unit_gradient_stabilizer(simplex, bow);
		
		for(int i=0;i<gradient_stabilizer.length;i++){
			//System.out.print(gradient_stabilizer[i]+" ");
		}
		//System.out.println();
		
		double[] rest = Gradients.centroid(simplex);
		double heightBowToTarget;
		//if(volumeSimplex > Math.pow(1e-10,Configuration.N))
			heightBowToTarget = Gradients.getHeightFromBowToTarget(volumeSimplex, volumeSimplex/2.0, arrow.getCoordinates().getCoordinatesAsDouble(), bow);
		//else
		//	heightBowToTarget = Gradients.getHeightFromBowToTarget(volumeSimplex, volumeSimplex, arrow.getCoordinates().getCoordinatesAsDouble(), bow);
		double[][] target = Gradients.getTargets(heightBowToTarget, arrow.getCoordinates().getCoordinatesAsDouble(), rest, bow);
		
		double distance = Line.norm(simplex.getBest().getCoordinates().getCoordinatesAsDouble(), arrow.getCoordinates().getCoordinatesAsDouble());
		
		//System.err.println(distance);
		Vertex bullseyeVertex = Line.shootcorrection(new Coordinates(centroid), gradient_stabilizer, distance, 4, target[1], gradients, simplex.getEvaluator(),simplex);		
		//if(Bounds.isCoordinateOutsideTheBounds(bullseyeVertex.getCoordinates().getCoordinatesAsDouble()))
		//		bullseyeVertex = Line.shootcorrection(new Coordinates(centroid), gradient_stabilizer, distance, 4, target[0], gradients, simplex.getEvaluator(),simplex);
		try {
			if(bullseyeVertex.getFitness() < 1e19)
					simplex.addVertex(bullseyeVertex);
			else{
				bullseyeVertex = Line.shootcorrection(new Coordinates(centroid), gradient_stabilizer, distance, 4, target[0], gradients, simplex.getEvaluator(),simplex);
				simplex.addVertex(bullseyeVertex);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return volumeSimplex;
	}

	
	//Correction with true gradients
	// mantaining 1/2 - 1
	public static double method7(Simplex simplex){
		
		double[] gradients = Gradients.gradient(simplex);
		double volumeSimplex = Initialization.simplex_volume(Configuration.N, Gradients.hackToGoArrayContainingASimplex(simplex));
		//Simplex without the arrow
		double[] centroid = Gradients.centroid(simplex);
		Vertex arrow = simplex.pollArrow();
		double[] bow = Gradients.getBowHyperplane(simplex);
		//double[] rest = Gradients.getRestArrow(gradients, arrow.getCoordinates().getCoordinatesAsDouble(), bow);
		double[] rest = Gradients.centroid(simplex);
		//double[] rest = simplex.getBest().getCoordinates().getCoordinatesAsDouble();
		double heightBowToTarget = Gradients.getHeightFromBowToTarget(volumeSimplex, volumeSimplex/2.0, arrow.getCoordinates().getCoordinatesAsDouble(), bow);
		double[][] target = Gradients.getTargets(heightBowToTarget, arrow.getCoordinates().getCoordinatesAsDouble(), rest, bow);
		double[] bullseye = Gradients.getIntersectionOfaVectorWithHyperplane(gradients, centroid, target[1]);	
		
	
		//New vertex in simplex without the arrow
		Vertex bullseyeVertex = simplex.addVertex(bullseye);
		//simplex.removeVertex(bullseyeVertex);
		

		//System.out.println(simplex.asString()+volumeSimplex);
		
		for(int i=0;i<4;i++){
			gradients = Gradients.gradient(simplex);
			centroid = Gradients.centroid(simplex);
			simplex.removeVertex(bullseyeVertex);
			bullseye = Gradients.getIntersectionOfaVectorWithHyperplane(gradients, centroid, target[1]);
			if(Bounds.isCoordinateOutsideTheBounds(bullseye)){
				simplex.addVertex(bullseyeVertex);
				break;
			}else
				bullseyeVertex = simplex.addVertex(bullseye);
			//System.out.println(simplex.asString()+volumeSimplex);
		}
		
		
		return volumeSimplex;
	}

	
	//Follows the gradient with shot-correction
	public static double method6(Simplex simplex){
		
		double[] gradients = Gradients.gradient(simplex);
		double volumeSimplex = Initialization.simplex_volume(Configuration.N, Gradients.hackToGoArrayContainingASimplex(simplex));
		//Simplex without the arrow
		double[] centroid = Gradients.centroid(simplex);
		Vertex arrow = simplex.pollArrow();
		double[] bow = Gradients.getBowHyperplane(simplex);
		//double[] rest = Gradients.getRestArrow(gradients, arrow.getCoordinates().getCoordinatesAsDouble(), bow);
		double[] rest = Gradients.centroid(simplex);
		//double[] rest = simplex.getBest().getCoordinates().getCoordinatesAsDouble();
		double heightBowToTarget = Gradients.getHeightFromBowToTarget(volumeSimplex, volumeSimplex, arrow.getCoordinates().getCoordinatesAsDouble(), bow);
		double[][] target = Gradients.getTargets(heightBowToTarget, arrow.getCoordinates().getCoordinatesAsDouble(), rest, bow);
		double[] bullseye = Gradients.getIntersectionOfaVectorWithHyperplane(gradients, centroid, target[1]);	
				
		//New vertex in simplex without the arrow
		Vertex best = simplex.getBest();
		Vertex bullseyeVertex = simplex.addVertex(bullseye);
		simplex.removeVertex(bullseyeVertex);
		
		
		double[] v = getNormalVectorFromHyperplane(bow);
		
	
		Vertex correctedshot = Line.optimizeline2(new Coordinates(bullseye), new Coordinates(centroid),heightBowToTarget/2.0 ,4, simplex.getEvaluator());
	
	
		simplex.addVertex(correctedshot);
		
		return volumeSimplex;
	}

	
	//Follows the gradient with shot-correction
	// mantaining 1/2
	public static double method5(Simplex simplex){
		
		double[] gradients = Gradients.gradient(simplex);
		double volumeSimplex = Initialization.simplex_volume(Configuration.N, Gradients.hackToGoArrayContainingASimplex(simplex));
		//Simplex without the arrow
		double[] centroid = Gradients.centroid(simplex);
		Vertex arrow = simplex.pollArrow();
		double[] bow = Gradients.getBowHyperplane(simplex);
		//double[] rest = Gradients.getRestArrow(gradients, arrow.getCoordinates().getCoordinatesAsDouble(), bow);
		double[] rest = Gradients.centroid(simplex);
		//double[] rest = simplex.getBest().getCoordinates().getCoordinatesAsDouble();
		double heightBowToTarget = Gradients.getHeightFromBowToTarget(volumeSimplex, volumeSimplex/2.0, arrow.getCoordinates().getCoordinatesAsDouble(), bow);
		double[][] target = Gradients.getTargets(heightBowToTarget, arrow.getCoordinates().getCoordinatesAsDouble(), rest, bow);
		double[] bullseye = Gradients.getIntersectionOfaVectorWithHyperplane(gradients, centroid, target[1]);	
		
		double[] symmetric_bullseye = Gradients.getSymmetric(bow, bullseye);
		
		//New vertex in simplex without the arrow
		Vertex best = simplex.getBest();
		Vertex bullseyeVertex = simplex.addVertex(bullseye);
		simplex.removeVertex(bullseyeVertex);
		
		
		double[] v = getNormalVectorFromHyperplane(bow);
		
//		for(int i=0;i<v.length;i++){
//			System.err.print(v[i]+",");
//		}
//		System.err.println();
//		
//		for(int i=0;i<bow.length;i++){
//			System.err.print(bow[i]+",");
//		}
//		System.err.println();
//		
//		for(int i=0;i<target[1].length;i++){
//			System.err.print(target[1][i]+",");
//		}
//		System.err.println();
//
//		for(int i=0;i<centroid.length;i++){
//			System.err.print(centroid[i]+",");
//		}
//		System.err.println();
		
		double[] stabilizer = Gradients.getIntersectionOfaVectorWithHyperplane(v, centroid, target[1]);
		double[] symmetric_stabilizer = Gradients.getIntersectionOfaVectorWithHyperplane(v, centroid, target[0]);
		
//		if(stabilizer==null){
//			System.err.println("eooooo");
//		}else{
//			System.err.println("s"+stabilizer.length);
//		}
		
		Vertex correctedshot = Line.optimizeline(new Coordinates(bullseye), new Coordinates(stabilizer), Line.norm(best.getCoordinates().getCoordinatesAsDouble(), arrow.getCoordinates().getCoordinatesAsDouble()), 4, simplex.getEvaluator());
	
		if(correctedshot == null){ // That is the case if the Line is out of the bounds (outside the box)
			//System.err.println("entro");
			correctedshot = Line.optimizeline(new Coordinates(symmetric_bullseye), new Coordinates(symmetric_stabilizer), Line.norm(best.getCoordinates().getCoordinatesAsDouble(), arrow.getCoordinates().getCoordinatesAsDouble()), 4, simplex.getEvaluator());
		}
		simplex.addVertex(correctedshot);
		
		return volumeSimplex;
	}
	
	private static double[] getNormalVectorFromHyperplane(double[] hyperplane){
		double[] v = new double[hyperplane.length -1];
		for(int i=0;i<v.length;i++){
			v[i] = hyperplane[i];
		}
		return v;
	}
	
	
	//Simply follow the gradient
	public static double[] method4(Simplex simplex, double[] trustedbow){
		
		double[] newtrustedbow = null;
		trustedbow = null;
		double[] gradients = Gradients.gradient(simplex);
		double volumeSimplex = Initialization.simplex_volume(Configuration.N, Gradients.hackToGoArrayContainingASimplex(simplex));
		//Simplex without the arrow
		double[] centroid = Gradients.centroid(simplex);
		Vertex arrow = simplex.pollArrow();
		double[] bow = Gradients.getBowHyperplane(simplex);
		//double[] rest = Gradients.getRestArrow(gradients, arrow.getCoordinates().getCoordinatesAsDouble(), bow);
		double[] rest = Gradients.centroid(simplex);
		//double[] rest = simplex.getBest().getCoordinates().getCoordinatesAsDouble();
		
		double heightBowToTarget;
		double[][] target;
		double[] bullseye;
		if(areBowsEqual(bow, trustedbow)){
			heightBowToTarget = Gradients.getHeightFromBowToTarget(volumeSimplex, volumeSimplex, arrow.getCoordinates().getCoordinatesAsDouble(), bow);
			target = Gradients.getTargets(heightBowToTarget, arrow.getCoordinates().getCoordinatesAsDouble(), rest, bow);
			bullseye = Gradients.getIntersectionOfaVectorWithHyperplane(gradients, centroid, target[1]);	
			newtrustedbow = null;
		}else{
			heightBowToTarget = Gradients.getHeightFromBowToTarget(volumeSimplex, volumeSimplex/2, arrow.getCoordinates().getCoordinatesAsDouble(), bow);
			target = Gradients.getTargets(heightBowToTarget, arrow.getCoordinates().getCoordinatesAsDouble(), rest, bow);
			bullseye = Gradients.getIntersectionOfaVectorWithHyperplane(gradients, centroid, target[1]);	
			newtrustedbow = bow;
		}
		
		//New vertex in simplex without the arrow
		Vertex bullseyeVertex = simplex.addVertex(bullseye);
		Vertex centroidVertex = simplex.addVertex(centroid);
		simplex.removeVertex(centroidVertex);
		
		return newtrustedbow;
	}
	
	private static boolean areBowsEqual(double[] bow1,double[] bow2){
		if (bow1 == null || bow2 == null){
			return false;
		}else if (bow1.length != bow2.length){
			return false;
		}else{
			for(int i=0;i<bow1.length;i++){
				if(bow1[i] != bow2[i]){
					return false;
				}
			}
		}
		return true;
	}
	
public static Vertex method3(Simplex simplex){
		
	double[] gradients = Gradients.gradient(simplex);
	double volumeSimplex = Initialization.simplex_volume(Configuration.N, Gradients.hackToGoArrayContainingASimplex(simplex));
	//Simplex without the arrow
	double[] centroid = Gradients.centroid(simplex);
	Vertex arrow = simplex.pollArrow();
	double[] bow = Gradients.getBowHyperplane(simplex);
	//double[] rest = Gradients.getRestArrow(gradients, arrow.getCoordinates().getCoordinatesAsDouble(), bow);
	double[] rest = Gradients.centroid(simplex);
	//double[] rest = simplex.getBest().getCoordinates().getCoordinatesAsDouble();
	double heightBowToTarget = Gradients.getHeightFromBowToTarget(volumeSimplex, volumeSimplex/2, arrow.getCoordinates().getCoordinatesAsDouble(), bow);
	double[][] target = Gradients.getTargets(heightBowToTarget, arrow.getCoordinates().getCoordinatesAsDouble(), rest, bow);
	double[] bullseye = Gradients.getIntersectionOfaVectorWithHyperplane(gradients, centroid, target[1]);	
	
	
	//New vertex in simplex without the arrow
	Vertex best = simplex.getBest();
	Vertex bullseyeVertex = simplex.addVertex(bullseye);
	double[] newcentroid = Gradients.centroid(simplex);
			//double[] mirroredcentroid = Gradients.getSymmetric(bow, newcentroid);
	Vertex newcentroidVertex = simplex.addVertex(newcentroid);
	simplex.removeVertex(newcentroidVertex);
	simplex.removeVertex(bullseyeVertex);
			//Vertex mirroredcentroidVertex = simplex.addVertex(mirroredcentroid);
	Vertex centroidVertex = simplex.addVertex(centroid);
	simplex.removeVertex(centroidVertex);
	

	if (!newcentroidVertex.better(centroidVertex) ){
		bullseye = Gradients.getIntersectionOfaVectorWithHyperplane(gradients, arrow.getCoordinates().getCoordinatesAsDouble(), target[0]);
		simplex.addVertex(bullseye);
	}else{
		simplex.addVertex(bullseyeVertex);	
	}
	
	
	
	return centroidVertex;
	}
	
	public static double[] orthogonal(double[] v){
		DoubleMatrix A = new DoubleMatrix(v);
		DoubleMatrix B = DoubleMatrix.zeros(1, 1);
		
		return Solve.solve(A, B).toArray();
		
	}

	//return previousbullseye vertex
	public static Vertex method2(Simplex simplex, Vertex previousbullseye){
		double[] gradients = Gradients.gradient(simplex);
		double volumeSimplex = Initialization.simplex_volume(Configuration.N, Gradients.hackToGoArrayContainingASimplex(simplex));
		//Simplex without the arrow
		double[] centroid = Gradients.centroid(simplex);
		Vertex arrow = simplex.pollArrow();
		double[] bow = Gradients.getBowHyperplane(simplex);
		//double[] rest = Gradients.getRestArrow(gradients, arrow.getCoordinates().getCoordinatesAsDouble(), bow);
		double[] rest = Gradients.centroid(simplex);
		//double[] rest = simplex.getBest().getCoordinates().getCoordinatesAsDouble();
		double heightBowToTarget = Gradients.getHeightFromBowToTarget(volumeSimplex, volumeSimplex/2, arrow.getCoordinates().getCoordinatesAsDouble(), bow);
		double[][] target = Gradients.getTargets(heightBowToTarget, arrow.getCoordinates().getCoordinatesAsDouble(), rest, bow);
		double[] bullseye = Gradients.getIntersectionOfaVectorWithHyperplane(gradients, centroid, target[1]);	
		
		
		//New vertex in simplex without the arrow
		Vertex best = simplex.getBest();
		Vertex bullseyeVertex = simplex.addVertex(bullseye);
		double[] newcentroid = Gradients.centroid(simplex);
				//double[] mirroredcentroid = Gradients.getSymmetric(bow, newcentroid);
		Vertex newcentroidVertex = simplex.addVertex(newcentroid);
		simplex.removeVertex(newcentroidVertex);
		simplex.removeVertex(bullseyeVertex);
				//Vertex mirroredcentroidVertex = simplex.addVertex(mirroredcentroid);
		Vertex centroidVertex = simplex.addVertex(centroid);
		simplex.removeVertex(centroidVertex);
		
	
		if (!newcentroidVertex.better(centroidVertex)){

			if(previousbullseye == null){
				double[] midpoint = Gradients.centroid(simplex);
				// the aim is the midpoint of the median  
				double[] aim = Gradients.getAim(midpoint, arrow.getCoordinates().getCoordinatesAsDouble());

				//System.err.println("A");
				
				Vertex aimVertex = simplex.addVertex(aim);	
				return null;
			}else{
				simplex.addVertex(arrow);
				simplex.removeVertex(previousbullseye);
				
				double[] oldbow = Gradients.getBowHyperplane(simplex);
				double[] newpoint = Gradients.getSymmetric(oldbow, previousbullseye.getCoordinates().getCoordinatesAsDouble());
				
				//System.err.println("B");
			
				simplex.addVertex(newpoint);
				return null;
			}
			           //System.err.println("Size "+simplex.size());
		}else{
			//System.err.println("D");
			simplex.addVertex(bullseyeVertex);
			return bullseyeVertex;
		}
	
	}
	
	public static Vertex method1(Simplex simplex){
		
		double[] gradients = Gradients.gradient(simplex);
		double volumeSimplex = Initialization.simplex_volume(Configuration.N, Gradients.hackToGoArrayContainingASimplex(simplex));
		//Simplex without the arrow
		double[] centroid = Gradients.centroid(simplex);
		Vertex arrow = simplex.pollArrow();
		double[] bow = Gradients.getBowHyperplane(simplex);
		//double[] rest = Gradients.getRestArrow(gradients, arrow.getCoordinates().getCoordinatesAsDouble(), bow);
		double[] rest = Gradients.centroid(simplex);
		//double[] rest = simplex.getBest().getCoordinates().getCoordinatesAsDouble();
		double heightBowToTarget = Gradients.getHeightFromBowToTarget(volumeSimplex, volumeSimplex/2, arrow.getCoordinates().getCoordinatesAsDouble(), bow);
		double[][] target = Gradients.getTargets(heightBowToTarget, arrow.getCoordinates().getCoordinatesAsDouble(), rest, bow);
		double[] bullseye = Gradients.getIntersectionOfaVectorWithHyperplane(gradients, centroid, target[1]);	
		
		
		//New vertex in simplex without the arrow
		Vertex best = simplex.getBest();
		Vertex bullseyeVertex = simplex.addVertex(bullseye);
		double[] newcentroid = Gradients.centroid(simplex);
				//double[] mirroredcentroid = Gradients.getSymmetric(bow, newcentroid);
		Vertex newcentroidVertex = simplex.addVertex(newcentroid);
		simplex.removeVertex(newcentroidVertex);
		simplex.removeVertex(bullseyeVertex);
				//Vertex mirroredcentroidVertex = simplex.addVertex(mirroredcentroid);
		Vertex centroidVertex = simplex.addVertex(centroid);
		simplex.removeVertex(centroidVertex);
		
	
		if (!newcentroidVertex.better(centroidVertex) ){

			double[] midpoint = Gradients.centroid(simplex);
			// the aim is the midpoint of the median  
			double[] aim = Gradients.getAim(midpoint, arrow.getCoordinates().getCoordinatesAsDouble());

			Vertex aimVertex = simplex.addVertex(aim);	
            //System.err.println("Size "+simplex.size());
		}else{
			simplex.addVertex(bullseyeVertex);
		}
		
//		if (newcentroidVertex.better(centroidVertex)){
//			simplex.addVertex(bullseyeVertex);
//		}else{
//			if(!bullseyeVertex.better(best)){
//				 //Calculate the median going from the best vertex to the midpoint of the opposite hyperplane
//                 double[] midpoint = Gradients.centroid(simplex);
//                  // the aim is the midpoint of the median  
//                 aim = Gradients.getAim(midpoint, arrow.getCoordinates().getCoordinatesAsDouble());
//
//                 Vertex aimVertex = simplex.addVertex(aim);
//			}else{
//				 //next steps to get the original simplex
//
//                 
//                 simplex.addVertex(arrow);
//                 //This step is to get the hyperplane after removing the best
//                 simplex.removeVertex(best);
//
//                 //Calculate the median going from the best vertex to the midpoint of the opposite hyperplane
//                 double[] midpoint = Gradients.centroid(simplex);
//                  // the aim is the midpoint of the median  
//                 aim = Gradients.getAim(midpoint, best.getCoordinates().getCoordinatesAsDouble());
//
//                 Vertex aimVertex = simplex.addVertex(aim);
//			}
//		}
		
		return centroidVertex;
	}
	

}
